package com.abe.bathsystem.contract;


import net.yet.campusdev.R;

import com.abe.bathsystem.base.ManagerAPP;
import com.abe.bathsystem.entity.serial.SerialDataEntity;
import com.abe.bathsystem.utils.NormalUtils;
import com.abe.libcore.utils.normal.ThreadPoolUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;

public class SerialPortModel implements SerialPortContract.Model {
    private static SerialPortModel serialPortModel;
    private static SerialPortContract.SerialPortPresenter.ISerialPortBack serialPortCallBack;
    //**************************** code标识 ****************************/
    /**
     * 错误
     */
    public static final int CODE_ERROR = 0x001;
    /**
     * 串口开启成功
     */
    public static final int CODE_OPEN_SUCCESS = 0x002;
    /**
     * 串口开启失败
     */
    public static final int CODE_CLOSE_SUCCESS = 0x003;
    /**
     * 下发命令成功
     */
    public static final int CODE_SEND_DATA_SUCCESS = 0x004;
    /**
     * 数据接收成功
     */
    public static final int CODE_RECEIVE_DATA_SUCCESS = 0x005;
    /**
     * 数据接收失败
     */
    public static final int CODE_RECEIVE_DATA_FAILED = 0x006;
    /**
     * 数据通道
     */
    private OutputStream mOutputStream;
    private InputStream mInputStream;
    /**
     * 操作线程
     */
    private ReadThread3 mReadThread;
    private int type;

    /**
     * sleep时间(ms)
     */
    private int sleepTime = 12;
    /**
     * 关联变量，当发送读命令的时候关联，当接受完一次数据的时候解除关联
     */
    private boolean relationRead = false;

    private byte[] currentCommand;
    private boolean isCurrentTest;
    //private StringBuilder //serialPortBuilder=new StringBuilder();

    private SerialPortModel() {
    }

    /**
     * @param callback callback
     * @return SerialPortModelImp
     */
    public static SerialPortModel from(SerialPortContract.SerialPortPresenter.ISerialPortBack callback) {
        serialPortCallBack = callback;
        if (serialPortModel == null) {
            synchronized (SerialPortModel.class) {
                if (serialPortModel == null)
                    serialPortModel = new SerialPortModel();
            }
        }
        return serialPortModel;
    }

    @Override
    public void openSerialPort(int type) {
        try {
            this.type = type;
            if (ManagerAPP.getInstance().getSerialPort(type) != null) {
                mInputStream = ManagerAPP.getInstance().getSerialPort(type)
                        .getInputStream();
                mOutputStream = ManagerAPP.getInstance().getSerialPort(type)
                        .getOutputStream();
                /* 串口开启成功 */
                serialPortCallBack.onResult(CODE_OPEN_SUCCESS, null, null);
                /* 开启读数据等待 */
                mReadThread = new ReadThread3();
                mReadThread.start();
            } else {
                serialPortCallBack.onResult(CODE_ERROR, null,
                        NormalUtils.getString(R.string.serialport_open_error));
            }
        } catch (InvalidParameterException e) {
            e.printStackTrace();
            serialPortCallBack.onResult(CODE_ERROR, null,
                    NormalUtils.getString(R.string.serialport_open_error));
        } catch (SecurityException e) {
            e.printStackTrace();
            serialPortCallBack.onResult(CODE_ERROR, null,
                    NormalUtils.getString(R.string.serialport_open_error));
        } catch (IOException e) {
            e.printStackTrace();
            serialPortCallBack.onResult(CODE_ERROR, null,
                    NormalUtils.getString(R.string.serialport_open_error));
        }

    }

    @Override
    public void sendCommand(byte[] buffer, boolean isTest) {
        this.currentCommand = buffer;
        this.isCurrentTest = isTest;
        if (mOutputStream != null) {
            if (buffer != null) {
                try {
                    /* 读命令，开启关联*/
                    relationRead = true;
                    ////serialPortBuilder.append("开启读").append("\n");
                    mOutputStream.write(buffer);
                    serialPortCallBack.onResult(CODE_SEND_DATA_SUCCESS, null,
                            null);
                    // receiveData();
                } catch (IOException e) {
                    e.printStackTrace();
                    serialPortCallBack.onResult(CODE_ERROR, null, NormalUtils
                            .getString(R.string.serialport_send_error));
                }
            } else {
                serialPortCallBack.onResult(CODE_ERROR, null,
                        "Command data null ");
            }
        } else {
            serialPortCallBack.onResult(CODE_ERROR, null,
                    NormalUtils.getString(R.string.serialport_open_error));
        }
    }

    @SuppressWarnings("unused")
    private void receiveData() {
        ThreadPoolUtils.execute(new ReadThread2());
    }

    @Override
    public void closeSerialPort() {
        if (mReadThread != null) {
            mReadThread.interrupt();
        }
        try {
            if (mInputStream != null) {
                mInputStream.close();
                mInputStream = null;
            }
            if (mOutputStream != null) {
                mOutputStream.close();
                mOutputStream = null;
            }
            if (ManagerAPP.getInstance().getSerialPort(type) != null) {
                ManagerAPP.getInstance().closeSerialPort(type);
            }
            /* 串口关闭成功 */
            serialPortCallBack.onResult(CODE_CLOSE_SUCCESS, null, null);
        } catch (IOException e) {
            e.printStackTrace();
            serialPortCallBack.onResult(CODE_ERROR, null,
                    NormalUtils.getString(R.string.serialport_close_error));
        }
        //NormalUtils.saveCrashInfo2File("串口使用日志",//serialPortBuilder.toString());
    }

    private class ReadThread3 extends Thread {

        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                /*通过关联变量，判断时候读*/
                while (!relationRead) ;
                {
                    //serialPortBuilder.append("读开始").append("\n");
                    try {
                        /* sleep */
                        Thread.sleep(sleepTime);
                        /* 读数据 */
                        int size;
                        byte[] buffer = new byte[64];
                        if (mInputStream == null)
                            return;
                        size = mInputStream.read(buffer);
                        //serialPortBuilder.append("读结束").append("\n");
                        /* 读数据完成结束此次通信关联 */
                        relationRead = false;
                        if (size > 0) {
                            //serialPortBuilder.append("读到数据").append("\n");
                            serialPortCallBack.onResult(
                                    CODE_RECEIVE_DATA_SUCCESS,
                                    new SerialDataEntity(currentCommand, buffer, size, isCurrentTest), null);
                        } else {
                            //serialPortBuilder.append("未读到数据").append("\n");
                            serialPortCallBack.onResult(CODE_RECEIVE_DATA_FAILED, null, null);
                        }
                    } catch (Exception e) {
                        //serialPortBuilder.append("异常").append("\n");
                        //serialPortBuilder.append("读结束").append("\n");
                        /* 出现异常，结束此次通信关联 */
                        relationRead = false;
                        e.printStackTrace();
                        return;
                    }
                }
            }
        }
    }


    private class ReadThread2 implements Runnable {

        @Override
        public void run() {
            try {
                Thread.sleep(120);
                int size;
                byte[] buffer = new byte[64];
                if (mInputStream == null)
                    return;
                size = mInputStream.read(buffer);
                if (size > 0) {
                    serialPortCallBack.onResult(CODE_RECEIVE_DATA_SUCCESS,
                            new SerialDataEntity(currentCommand, buffer, size, isCurrentTest), null);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
    }

    @SuppressWarnings("unused")
    private class ReadThread extends Thread {

        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                int size;
                try {
                    byte[] buffer = new byte[64];
                    if (mInputStream == null)
                        return;
                    size = mInputStream.read(buffer);
                    if (size > 0) {
                        serialPortCallBack.onResult(CODE_RECEIVE_DATA_SUCCESS,
                                new SerialDataEntity(currentCommand, buffer, size, isCurrentTest), null);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    return;
                }
            }
        }
    }

    /**
     * 将16进制byte[]转化为相应字符串
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int x : src) {
            int v = x & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

}
